package com.cloudptt.api.product.func.call.group.fsm.floor;

import android.content.Context;

import com.cloudptt.api.comm.CauseCont;
import com.cloudptt.api.comm.CheckData;
import com.cloudptt.api.comm.CommDlg;
import com.cloudptt.api.comm.Common;
import com.cloudptt.api.models.ErrInfo;
import com.cloudptt.api.models.ExtStrInfo;
import com.cloudptt.api.models.call.RtcpMsg;
import com.cloudptt.api.pjsua2.MyCall;
import com.cloudptt.api.product.func.addr.IAddrOp;
import com.cloudptt.api.product.func.call.CallAttr;
import com.cloudptt.api.product.func.call.CallConst;
import com.cloudptt.api.product.func.call.CallTimer;
import com.cloudptt.api.product.func.call.group.GroupCallSpeakListener;
import com.cloudptt.api.product.func.call.group.fsm.IRollback;
import com.cloudptt.api.product.log.Log;
import com.cloudptt.api.product.operator.CallOperator;
import com.cloudptt.api.product.res.Resource;
import com.mcptt.config.model.McIdInfo;
import com.mcptt.db.model.AddrInfo;

public class FloorAgent implements ISubState,IRollback
{
	public final static String Log_Key = "FloorAgent";
	private ISubState currentState = null;
	private GroupCallSpeakListener listener = null;
	private Context ctx = null;
	private String callIdStr = MyCall.DEF_CALL_ID_STR;
	private CallOperator operator = null;
	private IAddrOp addOp = null;
	private IRollback rollback = null;
	private CallTimer callTimer = null;

	private AddrInfo callInfo = null;
	private AddrInfo floorUserInfo = null;
	private String callKey = null;

	private CallAttr callAttr = null;
	private McIdInfo mcIdInfo = null;
	private boolean isIdle = false;


	public FloorAgent(Context ctx,String callIdStr,String callKey,CallOperator operator,IAddrOp addOp,CallTimer callTimer,IRollback rollback)
	{
		Log.d(FloorAgent.Log_Key, "FloorAgent");
		this.ctx = ctx;
		this.callIdStr = callIdStr;
		this.callKey = callKey;
		this.callTimer = callTimer;
		this.operator = operator;
		this.addOp = addOp;
		this.rollback = rollback;
		AddrInfo info = addOp.getCurGroupInfo();
		String groupNum = info.getMcId();
		int pri = info.getLevel();
		this.currentState = new FloorNoPermissionState(ctx,this,groupNum,pri);
	}
	
	public void setListener(GroupCallSpeakListener listener)
	{
		this.listener = listener;
	}
	public void updateCallIdStr(String callIdStr)
	{
		this.callIdStr = this.callIdStr;
	}

	public void goToState(int nextState,RtcpMsg msg)
	{
		ISubState state = null;
		Log.d(FloorAgent.Log_Key, "goToState:["+ CallConst.stateTag(this.currentState.getState()) +
				" to "+ CallConst.stateTag(nextState) + "]");

			switch (nextState) {
			case CallConst.FloorState_NoPermission:
				AddrInfo info = addOp.getCurGroupInfo();
				String groupNum = info.getMcId();
				int pri = info.getLevel();
				if(msg != null) {
					groupNum = msg.getValue(RtcpMsg.Key_To);
					String val = msg.getValue(RtcpMsg.Key_Prio);
					pri = CheckData.parseInt(val);
				}
				state = new FloorNoPermissionState(ctx,this,groupNum,pri);
				break;
			case CallConst.FloorState_PendingRequset:
				state = new FloorPendingRequestState(ctx,this);
				break;
			case CallConst.FloorState_Permission:
				info = addOp.getCurGroupInfo();
				groupNum = info.getMcId();
				pri = info.getLevel();
				if(msg != null) {
					groupNum = msg.getValue(RtcpMsg.Key_To);
					String val = msg.getValue(RtcpMsg.Key_Prio);
					pri = CheckData.parseInt(val);
				}
				state = new FloorPermissionState(ctx,this,groupNum,pri);
				break;
			case CallConst.SpeakState_PendingRelease:
				state = new FloorPendingReleaseState(ctx,this);
				break;
			default:
				Log.e(FloorAgent.Log_Key, "Illegal state="+ nextState);
				return;//!!!
			}
			this.setCurrentState(state);
			if(nextState == CallConst.FloorState_NoPermission
					&& msg != null)
			{
				this.receiveRtcpMsg(msg);
			}
	}
	
	private void setCurrentState(ISubState currentState) 
	{
		this.currentState.destory();
		this.currentState = currentState;
		int state = currentState.getState();
		if(listener != null)
		{
			listener.updateSpeakState(callKey,state);
		}
		if(currentState.getState() != CallConst.FloorState_Permission)
		{
			if(this.listener != null)
			{
				listener.updateSpeakDuration(callKey, "");
			}
		}
	}
	
	public void updateSpeakPermissionNum(String callType,String newNum,String num)
	{
		Log.d(FloorAgent.Log_Key, "FloorAgent updateSpeakPermissionNum callType = " + callType +" newNum = " + newNum+" num = " + num);
		if(listener != null
				&& num != null)
		{
			if(num.equals(""))
			{
				if(RtcpMsg.isGroupCall(callType)) {
					callInfo = addOp.getGroupInfoByNum(newNum);
					floorUserInfo = addOp.getUserInfoByNum(newNum, num);
				}
				else
				{
					callInfo = addOp.getUserInfoByNum(newNum);
					floorUserInfo = addOp.getUserInfoByNum(num);
//					callInfo = floorUserInfo;
				}
				listener.updateSpeakPermissionInfo(callKey, callInfo,null);
				floorUserInfo = null;
			}
			else
			{
				if(RtcpMsg.isGroupCall(callType)) {
					callInfo = addOp.getGroupInfoByNum(newNum);
					floorUserInfo = addOp.getUserInfoByNum(newNum, num);
				}
				else {
					callInfo = addOp.getUserInfoByNum(newNum);
					floorUserInfo = addOp.getUserInfoByNum(num);
//					callInfo = floorUserInfo;
				}
				listener.updateSpeakPermissionInfo(callKey, callInfo,floorUserInfo);
				
				if(operator != null)
				{
					operator.requestAudioFocus(true);
				}
			}
		}
	}

	public void updateCallDuration(int sec)
	{
		if(this.callTimer.getT180() > sec) {
			sec = this.callTimer.getT180() - sec;
		}
		else
		{
			sec = 0;
		}
		String timeDesc = Common.getTime(sec);
		if(this.listener != null)
		{
			listener.updateSpeakDuration(callKey, ""+ timeDesc);
		}
	}
	
	public int getCurrentState()
	{
		return this.currentState.getState();
	}

	public int doUserAction(int action)
	{
		Log.d( FloorAgent.Log_Key,
				CallConst.stateTag(this.currentState.getState()) + " doUserAction = " + CallConst.userActionTag( action ));
		return this.currentState.doUserAction(action);
	}

	public void receiveRtcpMsg(RtcpMsg msg)
	{
		Log.d(FloorAgent.Log_Key, CallConst.stateTag(this.currentState.getState()) + " receiveRtcpMsg msg = " + msg);
		this.currentState.receiveRtcpMsg(msg);
		String title = msg.getTitle();
		Log.d(FloorAgent.Log_Key, "receiveRtcpMsg agent title = " + title);
		if(title.equals(RtcpMsg.Title_FLOOR_DENY))
		{
			String callType = msg.getValue(RtcpMsg.Key_CallType);
			String reason = msg.getValue(RtcpMsg.Key_Reason);
			Log.d(FloorAgent.Log_Key, "receiveRtcpMsg agent reason = " + reason);
			String errStr =  Resource.getString("call_desc_deny_" + reason);//ctx.getString(R.string.operator_null);
			CommDlg.showToast(ctx,errStr);
			if (floorUserInfo != null) {
				currentState.updateTakenUser(callType, callInfo,floorUserInfo);
			}
		}

		String groupId = msg.getValue("groupId");
		AddrInfo info = addOp.getCurGroupInfo();
		if(info !=  null
			&& info.isSameOne(groupId)) {
			if (!isIdle && msg.isIdle()
					&& this.getState() == CallConst.FloorState_NoPermission) {
				isIdle = true;
//				if (operator != null) {
//					operator.startSoundPlayer(PromptTone.Type_End);
//				}
			}
			if (msg.isTaken()) {
				isIdle = false;
			}
		}
	}

	public void updateTakenUser(String callType,AddrInfo gInfo,AddrInfo user)
	{}
	
	public void showTalkEndToast()
	{
		String errStr = Resource.getString("e_pttfloorrelreq_1");
		CommDlg.showToast(ctx, errStr);
	}
	
	public int getState()
	{
		return this.currentState.getState();
	}
	public CallTimer getCallTimer() {
		return callTimer;
	}

	public void updateTime(CallTimer timer) {
		this.callTimer.updateTime(timer);
	}
	public void rollback()
	{
		if(rollback != null)
		{
			rollback.rollback();
		}
	}
	
	
	protected int floorRequest()
	{
		Context ctx = this.getCtx();
		if(null == operator
				|| null == ctx)
		{
			String errStr =  Resource.getString("operator_null");//ctx.getString(R.string.operator_null);
			CommDlg.showToast(ctx,errStr);
			return CauseCont.OperateCheck_Sys_UserKeyNull;
		}
		String gNum = addOp.getCurGroupInfo().getMcId();//callAttr.getGroupInfo().getMcId();
		int level =addOp.getCurGroupInfo().getLevel();
		String uName = mcIdInfo.getUserId();
		int result = operator.requestSpeaking(callIdStr,level,gNum,uName);
		if(result != CauseCont.OperateCheck_Suc) 
		{
			String errStr = CauseCont.getOperateCheckErrStr(result,ctx);
			CommDlg.showToast(ctx,errStr);
			return result;
		}
		return CauseCont.OperateCheck_Suc;
	}
	
	protected int floorRelease()
	{
		Context ctx = this.getCtx();
		if(null == operator
				|| null == ctx)
		{
			String errStr =  Resource.getString("operator_null");//ctx.getString(R.string.operator_null);
			CommDlg.showToast(ctx,errStr);
			return CauseCont.OperateCheck_Sys_UserKeyNull;
		}
		String gNum = addOp.getCurGroupInfo().getMcId();//callAttr.getGroupInfo().getMcId();
		int level =addOp.getCurGroupInfo().getLevel();
		String uName = mcIdInfo.getUserId();
		int result = operator.releaseSpeaking(callIdStr,level,gNum,uName);
		if(result != CauseCont.OperateCheck_Suc) 
		{
			String errStr = CauseCont.getOperateCheckErrStr(result,ctx);
			CommDlg.showToast(ctx,errStr);
			return result;
		}
		return CauseCont.OperateCheck_Suc;
	}

	protected int clearCurGroup()
	{
		Context ctx = this.getCtx();
		if(null == operator
				|| null == ctx)
		{
			String errStr =  Resource.getString("operator_null");//ctx.getString(R.string.operator_null);
			CommDlg.showToast(ctx,errStr);
			return CauseCont.OperateCheck_Sys_UserKeyNull;
		}
		int result = operator.clearCurGroup(callIdStr);
		if(result != CauseCont.OperateCheck_Suc)
		{
			String errStr = CauseCont.getOperateCheckErrStr(result,ctx);
			CommDlg.showToast(ctx,errStr);
			return result;
		}
		return CauseCont.OperateCheck_Suc;
	}
	
	protected void opAudioMedia(int opType)
	{
		Context ctx = this.getCtx();
		if(null == operator
				|| null == ctx)
		{
			String errStr =  Resource.getString("operator_null");//ctx.getString(R.string.operator_null);
			CommDlg.showToast(ctx,errStr);
			return;
		}
		
		int result = operator.opAudioMedia(callIdStr,opType);
		if(result != CauseCont.OperateCheck_Suc) 
		{
			String errStr = CauseCont.getOperateCheckErrStr(result,ctx);
			CommDlg.showToast(ctx,errStr);
			return;
		}
	}


	
	public AddrInfo getFloorUserInfo() {
		return floorUserInfo;
	}

	public void setDefaultGroupInfo(AddrInfo info)
	{
		floorUserInfo = null;
	}

	public void setFloorInfo(CallAttr callAttr,McIdInfo mcIdInfo)
	{
		this.callAttr = callAttr;
		this.mcIdInfo = mcIdInfo;
	}

	@Override
	public void destory() {
		// TODO Auto-generated method stub
		this.currentState.destory();
	}
	public void notifyDenyCause(int cause)
	{
		ErrInfo errInfo = new ErrInfo(ExtStrInfo.Title_CallDescDeny,cause);
		if( errInfo != null )
		{
			String errStr = errInfo.getErrDesc();
			CommDlg.show(ctx, errStr);
		}
	}
	
	public Context getCtx() {
		return ctx;
	}

	public CallOperator getOperator() {
		return operator;
	}
	
	public void clearResource()
	{
		currentState.destory();
		currentState = null;
		listener = null;
		ctx = null;
		operator = null;
		callTimer = null;
		rollback = null;
	}
}
